package com.test.qpbgboot.schedule.service.impl;

import com.test.qpbgboot.backend.pojo.entity.MerchantAccountLog;
import com.test.qpbgboot.backend.service.MerchantAccountService;
import com.test.qpbgboot.base.constants.RabbitMQConstants;
import com.test.qpbgboot.base.enums.*;
import com.test.qpbgboot.base.exception.ServiceException;
import com.test.qpbgboot.base.quartz.AutoAttendedJob;
import com.test.qpbgboot.base.rabbitmq.RabbitMQProducer;
import com.test.qpbgboot.base.response.ResultStatus;
import com.test.qpbgboot.base.service.PayService;
import com.test.qpbgboot.base.utils.BaseUtils;
import com.test.qpbgboot.schedule.mapper.EscortScheduleMapper;
import com.test.qpbgboot.schedule.mapper.OrderMapper;
import com.test.qpbgboot.schedule.mapper.RoomScheduleMapper;
import com.test.qpbgboot.schedule.pojo.dto.*;
import com.test.qpbgboot.schedule.pojo.entity.OrderInfo;
import com.test.qpbgboot.schedule.pojo.vo.EscortScheduleVO;
import com.test.qpbgboot.schedule.pojo.vo.OrderInfoVO;
import com.test.qpbgboot.schedule.pojo.vo.RoomScheduleVO;
import com.test.qpbgboot.schedule.service.OrderService;
import com.test.qpbgboot.schedule.service.ScheduleService;
import com.test.qpbgboot.show.mapper.EscortMapper;
import com.test.qpbgboot.show.mapper.RoomMapper;
import com.test.qpbgboot.show.mapper.ShopMapper;
import com.test.qpbgboot.show.pojo.dto.EscortQuery;
import com.test.qpbgboot.show.pojo.dto.RoomQuery;
import com.test.qpbgboot.show.pojo.dto.ShopQuery;
import com.test.qpbgboot.show.pojo.vo.EscortVO;
import com.test.qpbgboot.show.pojo.vo.RoomVO;
import com.test.qpbgboot.show.pojo.vo.ShopVO;
import com.test.qpbgboot.user.mapper.PersonalAccountLogMapper;
import com.test.qpbgboot.user.mapper.PersonalAccountMapper;
import com.test.qpbgboot.user.mapper.UserMapper;
import com.test.qpbgboot.user.pojo.entity.PersonalAccountLog;
import com.test.qpbgboot.user.pojo.vo.PersonalAccountVO;
import com.test.qpbgboot.user.pojo.vo.UserVO;
import com.test.qpbgboot.user.service.AccountService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private EscortMapper escortMapper;
    @Autowired
    private RoomMapper roomMapper;
    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private EscortScheduleMapper escortScheduleMapper;
    @Autowired
    private RoomScheduleMapper roomScheduleMapper;
    @Autowired
    private PersonalAccountMapper personalAccountMapper;
    @Autowired
    private PersonalAccountLogMapper personalAccountLogMapper;
    @Autowired
    private PayService payService;
    @Autowired
    private ScheduleService scheduleService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private MerchantAccountService merchantAccountService;
    @Autowired
    private RabbitMQProducer rabbitMQProducer;
    @Value("${platform.account.name}")
    private String platformAccountName;


    @Override
    public List<OrderInfoVO> orderSelect(OrderQuery orderQuery) {
        if(orderQuery.getOrderStatusList()==null || orderQuery.getOrderStatusList().isEmpty()){
            orderQuery.setOrderStatusList(Collections.singletonList(orderQuery.getOrderStatus()));
        }
        log.debug("订单查询业务，参数:{}", orderQuery);
        List<OrderInfoVO> orderInfoVOList = orderMapper
                .selectOrderInfoVObyOrderQuery(orderQuery);
        if (orderInfoVOList != null && !orderInfoVOList.isEmpty()) {
            for (OrderInfoVO orderInfoVO : orderInfoVOList) {
                additionalField(orderInfoVO);
            }
        }
        log.debug("订单查询结果:{}", orderInfoVOList);
        return orderInfoVOList;
    }

    @Override
    public void orderCreate(OrderCreateParam orderCreateParam) {
        log.debug("订单创建业务，参数:{}", orderCreateParam);
        UserVO userVO = userMapper.selectUserVObyId(orderCreateParam.getUserId());
        if (userVO == null || userVO.getStatus()
                .equals(GeneralStatusEnum.DISABLE.getValue())) {
            throw new ServiceException(ResultStatus.INVALID_ID, "用户id无效");
        }

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderCreateParam, orderInfo);
        orderInfo.setOrderStatus(OrderStatusEnum.COMMITED.getValue());

        checkDateTime(orderInfo);
        checkRoomAndEscort(orderInfo);
        calculatePrice(orderInfo);

        orderMapper.insert(orderInfo);


        //跳过已创建和已提交阶段
        OrderUpdateParam orderUpdateParam = new OrderUpdateParam();
        BeanUtils.copyProperties(orderInfo, orderUpdateParam);
        orderUpdateParam.setOrderStatus(OrderStatusEnum.WAITING_PAY.getValue());
        orderUpdate(orderUpdateParam);
    }

    @Override
    public void orderUpdate(OrderUpdateParam orderUpdateParam) {
        log.debug("订单更新业务，参数:{}", orderUpdateParam);
        Long id = orderUpdateParam.getId();

        OrderQuery orderQuery = new OrderQuery();
        orderQuery.setId(id);
        List<OrderInfoVO> orderInfoVOList = orderMapper
                .selectOrderInfoVObyOrderQuery(orderQuery);
        if (orderInfoVOList == null || orderInfoVOList.isEmpty()) {
            throw new ServiceException(ResultStatus.INVALID_ID, "订单id无效");
        }

        OrderInfoVO orderInfoVO = orderInfoVOList.get(0);
        additionalField(orderInfoVO);

        String orderStatus = orderInfoVO.getOrderStatus();
        String newStatus = orderUpdateParam.getOrderStatus();
        if (newStatus.equals(OrderStatusEnum.CREATED.getValue())) {
            log.debug("玩家用户更新订单-业务");
            List<String> statusList = new ArrayList<>();
            statusList.add(OrderStatusEnum.CREATED.getValue());
            statusList.add(OrderStatusEnum.CANCELED.getValue());
            if (statusList.contains(orderStatus)) {
                checkAndUpdateDetail(orderUpdateParam, orderInfoVO);
            } else {
                throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态跳转错误");
            }
        } else if (newStatus.equals(OrderStatusEnum.COMMITED.getValue())) {
            log.debug("玩家用户提交订单-业务");
            if (orderStatus.equals(OrderStatusEnum.CREATED.getValue())) {
                checkAndUpdateDetail(orderUpdateParam, orderInfoVO);
            } else {
                throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态跳转错误");
            }
        } else if (newStatus.equals(OrderStatusEnum.WAITING_PAY.getValue())) {
            log.debug("店家确认订单-业务");
            System.out.println(orderStatus);
            if (orderStatus.equals(OrderStatusEnum.COMMITED.getValue())) {
                OrderInfo orderInfo = new OrderInfo();
                System.out.println("---------------------------------");
                BeanUtils.copyProperties(orderUpdateParam, orderInfo);
                checkDateTime(orderInfo);
                checkRoomAndEscort(orderInfo);
                escortScheduleSaveByOrder(orderInfoVO);
                roomScheduleSaveByOrder(orderInfoVO);
                orderChangeStatus(id,
                        orderUpdateParam.getShopMessage(),
                        OrderStatusEnum.WAITING_PAY);
                rabbitMQProducer.send(String.valueOf(id),
                        RabbitMQConstants.ORDER_WAITING_PAY_EXCHANGE,
                        RabbitMQConstants.ORDER_WAITING_PAY_ROUTING_KEY);
            } else {
                throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态跳转错误");
            }
        } else if (newStatus.equals(OrderStatusEnum.CANCELED.getValue())) {
            log.debug("取消订单-业务");
            List<String> statusList = new ArrayList<>();
            statusList.add(OrderStatusEnum.CREATED.getValue());
            statusList.add(OrderStatusEnum.COMMITED.getValue());
            statusList.add(OrderStatusEnum.WAITING_PAY.getValue());
            if (statusList.contains(orderStatus)) {
                scheduleRearrange(id);
                orderChangeStatus(id,
                        orderUpdateParam.getShopMessage(),
                        OrderStatusEnum.CANCELED);
            } else {
                throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态跳转错误");
            }
        } else if (newStatus.equals(OrderStatusEnum.WAITING_REFUND.getValue())) {
            log.debug("玩家用户发起退款-业务");
            if (orderStatus.equals(OrderStatusEnum.WAITING_ATTEND.getValue())) {
                orderChangeStatus(id, null, OrderStatusEnum.WAITING_REFUND);
            } else {
                throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态跳转错误");
            }
        } else if (newStatus.equals(OrderStatusEnum.ATTENDED.getValue())) {
            log.debug("店家确认玩家到场参加-业务");
            if (orderStatus.equals(OrderStatusEnum.WAITING_ATTEND.getValue())) {
                orderChangeStatus(id, null, OrderStatusEnum.ATTENDED);
            } else {
                throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态跳转错误");
            }
        } else {
            throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态跳转错误");
        }
    }

    @Override
    public void orderDelete(Long orderId) {
        log.debug("订单删除业务，参数:{}", orderId);
        OrderQuery orderQuery = new OrderQuery();
        orderQuery.setId(orderId);
        List<OrderInfoVO> orderInfoVOList = orderMapper
                .selectOrderInfoVObyOrderQuery(orderQuery);
        if (orderInfoVOList != null && !orderInfoVOList.isEmpty()) {
            if (orderInfoVOList.get(0).getOrderStatus()
                    .equals(OrderStatusEnum.CANCELED.getValue())) {
                orderMapper.deleteById(orderId);
            } else {
                throw new ServiceException(ResultStatus.INCORRECT_STATUS, "该状态的订单不能删除");
            }
        }
    }

    @Override
    public void orderPay(Long orderId) {
        log.debug("订单账户内支付业务，参数:{}", orderId);
        String orderNo = PayService.generateOrderNo();

        OrderInfoVO orderInfoVO = new OrderInfoVO();
        PersonalAccountVO personalAccountVO = new PersonalAccountVO();

        getAndCheck(orderId, orderInfoVO, personalAccountVO);
        if (personalAccountVO.getAccountBalance().compareTo(orderInfoVO.getPrice()) < 0) {
            throw new ServiceException(ResultStatus.INSUFFICIENT_BALANCE);
        }

        orderPaymentCompleted(orderInfoVO, orderNo, TransactionTypeEnum.EXPENDITURE);
    }

    @Override
    public String orderAlipay(Long orderId) {
        log.debug("订单支付宝支付，参数:{}", orderId);
        String orderNo = PayService.generateOrderNo();

        OrderInfoVO orderInfoVO = new OrderInfoVO();
        PersonalAccountVO personalAccountVO = new PersonalAccountVO();

        getAndCheck(orderId, orderInfoVO, personalAccountVO);

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVO, orderInfo);
        orderInfo.setOrderNo(orderNo);
        orderMapper.update(orderInfo);

        PersonalAccountLog accountLog = new PersonalAccountLog();
        accountLog.setPersonalId(personalAccountVO.getId());
        accountLog.setOrderNo(orderNo);
        accountLog.setAmount(orderInfo.getPrice());
        accountLog.setTMessage(orderInfoVO.getServiceName());
        accountLog.setTransactionType(
                TransactionTypeEnum.DIRECT_PAYMENT.getValue());
        accountLog.setPoints(0L);
        personalAccountLogMapper.insert(accountLog);
        String formPayStr = payService.payByAlipay(accountLog,
                "/v1/schedule/order/alipay-notify", "/pay");
        log.debug("支付宝支付页面:formPayStr={}", formPayStr);
        return formPayStr;
    }

    @Override
    public void orderAlipayNotify(Map<String, String> params) {
        log.debug("订单支付支付宝通知业务，参数:{}", params);

        payService.payNotifyByAlipay(params);

        String orderNo = params.get("out_trade_no");
        if ("TRADE_SUCCESS".equals(params.get("trade_status"))) {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setOrderNo(orderNo);
            List<OrderInfoVO> orderInfoVOList = orderMapper.selectOrderInfoVObyOrderQuery(orderQuery);
            if (orderInfoVOList == null || orderInfoVOList.isEmpty()) {
                throw new ServiceException(ResultStatus.INVALID_ID, "找不到该订单号的订单");
            }
            OrderInfoVO orderInfoVO = orderInfoVOList.get(0);

            orderPaymentCompleted(orderInfoVO, orderNo, TransactionTypeEnum.DIRECT_PAYMENT);
        } else {
            personalAccountLogMapper.deleteByOrderNo(orderNo);
            throw new ServiceException(ResultStatus.TRADE_FAILED);
        }
    }

    /**
     * 根据店家id取消所有还未提交的订单
     */
    @Override
    public void orderAllCancelByShopId(Long shopId) {
        log.debug("根据店家id取消所有订单-业务，参数:{}", shopId);
        OrderQuery orderQuery = new OrderQuery();
        orderQuery.setShopId(shopId);
        orderQuery.setOrderStatusList(
                Collections.singletonList(
                        OrderStatusEnum.CREATED.getValue()));
        List<OrderInfoVO> orderInfoVOList = orderMapper
                .selectOrderInfoVObyOrderQuery(orderQuery);
        if (orderInfoVOList != null && !orderInfoVOList.isEmpty()) {
            for (OrderInfoVO orderInfoVO : orderInfoVOList) {
                OrderUpdateParam orderUpdateParam = new OrderUpdateParam();
                BeanUtils.copyProperties(orderInfoVO, orderUpdateParam);
                orderUpdateParam.setOrderStatus(OrderStatusEnum.CANCELED.getValue());
                orderUpdate(orderUpdateParam);
            }
        }
    }

    /**
     * 预约开始时间前五分钟，自动把订单状态改为已参加，谢绝退款
     */
    @Override
    public void autoAttendedJobImpl(String orderNo) {
        log.debug("自动确认参加-业务，参数:{}", orderNo);

        OrderInfoVO orderInfoVO = orderMapper.selectOrderInfoVObyOrderNo(orderNo);
        if (orderInfoVO != null
                && orderInfoVO.getOrderStatus()
                .equals(OrderStatusEnum.WAITING_ATTEND.getValue())) {
            OrderInfo orderInfo = new OrderInfo();
            BeanUtils.copyProperties(orderInfoVO, orderInfo);
            orderInfo.setOrderStatus(OrderStatusEnum.ATTENDED.getValue());
            orderMapper.changeStatusAndMessage(orderInfo);
        } else {
            log.debug("玩家已确认参加");
        }
    }

    @Override
    public boolean checkOrderPaid(Long orderId) {
        log.debug("检查订单是否已经付款-业务 入参:orderId:{}", orderId);

        OrderQuery orderQuery = new OrderQuery();
        orderQuery.setId(orderId);
        orderQuery.setOrderStatusList(
                Collections.singletonList(
                        OrderStatusEnum.WAITING_PAY.getValue()));
        List<OrderInfoVO> orderInfoVOList =
                orderMapper.selectOrderInfoVObyOrderQuery(orderQuery);
        if (orderInfoVOList != null && !orderInfoVOList.isEmpty()) {
            Date updateTime = orderInfoVOList.get(0).getUpdateTime();
            Date checkTime = new Date(System.currentTimeMillis() - 5 * 60 * 1000);
            if (updateTime.before(checkTime)) {
                log.warn("订单付款已超时，取消订单 orderId:{}", orderId);
                OrderUpdateParam orderUpdateParam = new OrderUpdateParam();
                BeanUtils.copyProperties(orderInfoVOList.get(0), orderUpdateParam);
                orderUpdateParam.setOrderStatus(OrderStatusEnum.CANCELED.getValue());
                orderUpdate(orderUpdateParam);
                return false;
            }
        }
        log.debug("订单状态已改变");
        return true;
    }

    @Override
    public void orderRefund(Long id) {
        log.debug("订单退款-业务 入参:id:{}", id);
        //退款业务.......
        log.debug("实现退款业务");
        orderChangeStatus(id, null, OrderStatusEnum.END);
    }

    /**
     * orderInfoVO额外属性查找计算
     */
    private void additionalField(OrderInfoVO orderInfoVO) {
        log.debug("添加额外属性 orderInfoVO:{}", orderInfoVO);

        UserVO userVO =
                userMapper.selectUserVObyId(orderInfoVO.getUserId());
        orderInfoVO.setUsername(userVO.getUsername());

        Long roomId = orderInfoVO.getRoomId();
        if (roomId != null) {
            RoomQuery roomQuery = new RoomQuery();
            roomQuery.setId(roomId);
            List<RoomVO> roomVOList = roomMapper.selectRoomVObyRoomQuery(roomQuery);
            if (roomVOList != null && roomVOList.size() == 1) {
                orderInfoVO.setRoomName(roomVOList.get(0).getName());
                String roomImgs = roomVOList.get(0).getImgsUrl() + ",";
                orderInfoVO.setRoomImage(roomImgs.substring(0, roomImgs.indexOf(",")));
            } else {
                throw new ServiceException(ResultStatus.DIRTY_DATA, "异常的房间id");
            }
        }

        String escortIds = orderInfoVO.getEscortIds();
        if (escortIds != null && !escortIds.trim().isEmpty()) {
            List<Long> escortIdList = Arrays.stream(escortIds.split(","))
                    .map(Long::parseLong).collect(Collectors.toList());
            orderInfoVO.setEscortIdList(escortIdList);

            List<String> escortNameList = new ArrayList<>();
            List<String> escortImgList = new ArrayList<>();
            List<Boolean> escortCheckedList = new ArrayList<>();
            escortIdList.forEach(id -> {
                EscortQuery escortQuery = new EscortQuery();
                escortQuery.setId(id);
                List<EscortVO> escortVOList = escortMapper
                        .selectEscortVObyEscortQuery(escortQuery);
                if (escortVOList != null && escortVOList.size() == 1) {
                    escortNameList.add(escortVOList.get(0).getUsername());
                    escortImgList.add(escortVOList.get(0).getImgUrl());
                } else {
                    throw new ServiceException(ResultStatus.DIRTY_DATA, "异常的陪玩id");
                }
                if (orderInfoVO.getOrderStatus()
                        .equals(OrderStatusEnum.COMMITED.getValue())) {
                    EscortScheduleQuery escortScheduleQuery = new EscortScheduleQuery();
                    escortScheduleQuery.setEscortId(id);
                    escortScheduleQuery.setOrderId(orderInfoVO.getId());
                    List<EscortScheduleVO> escortScheduleVOList = escortScheduleMapper
                            .selectEscortScheduleVObyEscortScheduleQuery(escortScheduleQuery);
                    if (escortScheduleVOList == null || escortScheduleVOList.isEmpty()) {
                        escortCheckedList.add(false);
                    } else if (escortScheduleVOList.size() == 1) {
                        escortCheckedList.add(true);
                    } else {
                        throw new ServiceException(ResultStatus.DIRTY_DATA, "排班数据有误");
                    }
                }
            });

            String escortNameString = String.join(",", escortNameList);
            orderInfoVO.setEscortNameString(escortNameString);
            orderInfoVO.setEscortNameList(escortNameList);
            orderInfoVO.setEscortImgList(escortImgList);
            orderInfoVO.setEscortCheckedList(escortCheckedList.isEmpty() ?
                    null : escortCheckedList);
        }
        Long shopId = orderInfoVO.getShopId();
        if (shopId != null) {
            orderInfoVO.setShopName(shopMapper.selectShopNameById(shopId));
        } else {
            throw new ServiceException(ResultStatus.DIRTY_DATA, "异常的商店id");
        }
        String serviceName = "桌游房间预定：" + orderInfoVO.getShopName()
                + "的房间" + orderInfoVO.getRoomName() + "，日期：" + orderInfoVO.getAppointmentDate()
                + "，时间：" + orderInfoVO.getStartTime() + "-" + orderInfoVO.getEndTime();
        orderInfoVO.setServiceName(serviceName);
    }

    /**
     * 检查房间和陪玩id以及排班
     */
    private void checkRoomAndEscort(OrderInfo orderInfo) {
        log.debug("检查房间和陪玩id以及排班 orderInfo:{}", orderInfo);
        Long roomId = orderInfo.getRoomId();
        Long shopId = roomMapper.selectShopIdById(roomId);
        LocalDate appointmentDate = orderInfo.getAppointmentDate();
        LocalTime startTime = orderInfo.getStartTime();
        LocalTime endTime = orderInfo.getEndTime();

        if (shopId == null) {
            throw new ServiceException(ResultStatus.INVALID_ID, "房间id无效");
        } else {
            orderInfo.setShopId(shopId);
        }
        if (shopMapper.selectEnableCountById(shopId) != 1) {
            throw new ServiceException(ResultStatus.INVALID_ID, "房间对应的店家id无效");
        }

        scheduleService.checkRoomSchedule(roomId, appointmentDate, startTime, endTime);

        List<Long> escortIdList = orderInfo.getEscortIdList();
        if (escortIdList != null && !escortIdList.isEmpty()) {
            if (escortIdList.size() != escortMapper
                    .selectEnableCountByIdList(escortIdList)) {
                throw new ServiceException(ResultStatus.INVALID_ID, "陪玩id无效或重复");
            }
            for (Long escortId : escortIdList) {
                scheduleService.checkEscortSchedule(escortId, appointmentDate, startTime, endTime);
            }
            String escortIds = escortIdList.stream().map(String::valueOf)
                    .collect(Collectors.joining(","));
            orderInfo.setEscortIds(escortIds);
        }
    }

    /**
     * 检查预约时间，必须提前至少十五分钟预约，但是不能早一周以上
     */
    private void checkDateTime(OrderInfo orderInfo) {
        log.debug("检查预约时间 orderInfo:{}", orderInfo);
        LocalDate appointmentDate = orderInfo.getAppointmentDate();
        LocalTime startTime = orderInfo.getStartTime();
        LocalDateTime time = LocalDateTime.of(appointmentDate, startTime);
        LocalDateTime now = LocalDateTime.now();
        if (time.minusMinutes(15).isBefore(now)) {
            throw new ServiceException(
                    ResultStatus.SCHEDULE_NOT_ALLOWED,
                    "预约时间过近，请提前至少十五分钟预约");
        } else if (time.minusDays(7).isAfter(now)) {
            throw new ServiceException(
                    ResultStatus.SCHEDULE_NOT_ALLOWED,
                    "预约时间过远，请提前至多一周预约");
        }
    }

    /**
     * 计算价格
     */
    private void calculatePrice(OrderInfo orderInfo) {
        log.debug("计算价格业务，参数:{}", orderInfo);
        BigDecimal price = new BigDecimal(0);
        Duration duration = Duration.between(orderInfo.getStartTime(),
                orderInfo.getEndTime());
        BigDecimal hours = BigDecimal.valueOf(duration.toHours());
        if (duration.toMinutes() > 0) {
            hours = hours.add(BigDecimal.valueOf(1));
        }
        if (orderInfo.getRoomId() != null) {
            BigDecimal roomPrice = roomMapper.selectPriceById(orderInfo.getRoomId());
            if (roomPrice != null) {
                price = price.add(roomPrice.multiply(hours));
            } else {
                throw new ServiceException(ResultStatus.INVALID_ID, "房间价格异常");
            }
        }
        List<Long> escortIdList = orderInfo.getEscortIdList();
        if (escortIdList != null && !escortIdList.isEmpty()) {
            for (Long escortId : escortIdList) {
                BigDecimal escortPrice = escortMapper.selectPriceById(escortId);
                if (escortPrice != null) {
                    price = price.add(escortPrice.multiply(hours));
                } else {
                    throw new ServiceException(ResultStatus.INVALID_ID, "陪玩价格异常");
                }
            }
        }
        orderInfo.setPrice(price);
    }

    /**
     * 检查并更新订单详情
     */
    private void checkAndUpdateDetail(
            OrderUpdateParam orderUpdateParam, OrderInfoVO orderInfoVO) {
        log.debug("检查并更新订单详情 orderUpdateParam:{},orderInfoVO:{}",
                orderUpdateParam, orderInfoVO);
        if (!Objects.equals(roomMapper.selectShopIdById(
                orderUpdateParam.getRoomId()), orderInfoVO.getShopId())) {
            throw new ServiceException(ResultStatus.INVALID_ID, "修改订单不能跨店家");
        }

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderUpdateParam, orderInfo);
        checkDateTime(orderInfo);
        checkRoomAndEscort(orderInfo);

        calculatePrice(orderInfo);
        orderMapper.update(orderInfo);
    }

    /***
     * 订单状态修改
     */
    private void orderChangeStatus(Long id, String shopMessage, OrderStatusEnum orderStatusEnum) {
        log.debug("订单状态修改 id:{},orderStatusEnum:{}",
                id, orderStatusEnum);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(id);
        orderInfo.setOrderStatus(orderStatusEnum.getValue());
        orderInfo.setShopMessage(shopMessage);
        orderMapper.changeStatusAndMessage(orderInfo);
    }

    /**
     * 订单取消或退款后排班重排
     */
    private void scheduleRearrange(Long orderId) {
        log.debug("订单取消或退款后排班重排 orderId:{}", orderId);
        EscortScheduleQuery escortScheduleQuery = new EscortScheduleQuery();
        escortScheduleQuery.setOrderId(orderId);
        escortScheduleQuery.setStatus(EscortStatusEnum.BOOKED.getValue());
        List<EscortScheduleVO> escortScheduleVOList = escortScheduleMapper
                .selectEscortScheduleVObyEscortScheduleQuery(escortScheduleQuery);
        if (escortScheduleVOList != null && !escortScheduleVOList.isEmpty()) {
            for (EscortScheduleVO escortScheduleVO : escortScheduleVOList) {
                EscortScheduleSaveParam escortScheduleSaveParam =
                        new EscortScheduleSaveParam();
                BeanUtils.copyProperties(escortScheduleVO, escortScheduleSaveParam);
                escortScheduleSaveParam.setStatus(EscortStatusEnum.FREE.getValue());
                escortScheduleSaveParam.setOrderId(null);
                scheduleService.escortScheduleSave(escortScheduleSaveParam);
            }
        }

        RoomScheduleQuery roomScheduleQuery = new RoomScheduleQuery();
        roomScheduleQuery.setOrderId(orderId);
        roomScheduleQuery.setStatus(RoomStatusEnum.BOOKED.getValue());
        List<RoomScheduleVO> roomScheduleVOList = roomScheduleMapper
                .selectRoomScheduleVObyRoomScheduleQuery(roomScheduleQuery);
        if (roomScheduleVOList != null && !roomScheduleVOList.isEmpty()) {
            for (RoomScheduleVO roomScheduleVO : roomScheduleVOList) {
                RoomScheduleSaveParam roomScheduleSaveParam = new RoomScheduleSaveParam();
                BeanUtils.copyProperties(roomScheduleVO, roomScheduleSaveParam);
                roomScheduleSaveParam.setStatus(RoomStatusEnum.AVAILABLE.getValue());
                roomScheduleSaveParam.setOrderId(null);
                scheduleService.roomScheduleSave(roomScheduleSaveParam);
            }
        }
    }

    /**
     * 从订单号得到订单和账户信息，并且检查
     */
    private void getAndCheck(Long orderId, OrderInfoVO orderInfoVO,
                             PersonalAccountVO personalAccountVO) {
        log.debug("获取订单和账户信息 orderId:{}", orderId);
        OrderQuery orderQuery = new OrderQuery();
        orderQuery.setId(orderId);
        List<OrderInfoVO> orderInfoVOList = orderMapper
                .selectOrderInfoVObyOrderQuery(orderQuery);
        if (orderInfoVOList == null || orderInfoVOList.isEmpty()) {
            throw new ServiceException(ResultStatus.INVALID_ID, "订单id无效");
        }
        BeanUtils.copyProperties(orderInfoVOList.get(0), orderInfoVO);

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVO, orderInfo);
        checkDateTime(orderInfo);
        if (!orderInfoVO.getOrderStatus()
                .equals(OrderStatusEnum.WAITING_PAY.getValue())) {
            throw new ServiceException(ResultStatus.INCORRECT_STATUS, "状态不为待付款");
        }

        PersonalAccountVO accountVO = personalAccountMapper
                .selectPersonalAccountVObyUserId(orderInfoVO.getUserId());
        if (accountVO == null) {
            throw new ServiceException(ResultStatus.DIRTY_DATA, "用户id无效");
        }
        if (!accountVO.getStatus().equals(GeneralStatusEnum.ENABLE.getValue())) {
            throw new ServiceException(ResultStatus.INVALID_ID, "用户id失效");
        }
        BeanUtils.copyProperties(accountVO, personalAccountVO);

        log.debug("获取订单和账户信息 orderId:{},orderInfoVO:{},personalAccountVO:{}",
                orderId, orderInfoVO, personalAccountVO);
    }

    /**
     * 订单支付完成后的各项事宜
     */
    private void orderPaymentCompleted(
            OrderInfoVO orderInfoVO, String orderNo,
            TransactionTypeEnum transactionType) {
        log.debug("订单完成后的各种处理 orderInfoVO:{},orderNo:{},transactionType:{}",
                orderInfoVO, orderNo, transactionType);
        orderInfoVO.setOrderNo(orderNo);
        personalAccountUpdate(orderInfoVO, transactionType);

        merchantAccountUpdate(orderInfoVO, orderNo);

        //设定自动确认参加的定时任务
        setAutoAttendedJob(orderInfoVO, orderNo);

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVO, orderInfo);
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(OrderStatusEnum.WAITING_ATTEND.getValue());
        orderMapper.pay(orderInfo);
    }

    /**
     * 设定自动确认参加的定时任务
     */
    private void setAutoAttendedJob(OrderInfoVO orderInfoVO, String orderNo) {
        log.debug("设置-自动确认参加-定时任务 orderInfoVO:{},orderNo:{}", orderInfoVO, orderNo);
        LocalDate day = orderInfoVO.getAppointmentDate();
        LocalTime time = orderInfoVO.getStartTime();
        LocalDateTime triggerDateTime = LocalDateTime.of(day, time).minusMinutes(5);//预约开始时间前五分钟
        Date triggerTime = BaseUtils.toDate(triggerDateTime);
        try {
            AutoAttendedJob.setJob(orderNo, triggerTime);
        } catch (SchedulerException e) {
            log.error("设置-自动确认参加-定时任务-失败 message:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 房间排班表修改
     */
    private void roomScheduleSaveByOrder(OrderInfoVO orderInfoVO) {
        log.debug("房间排班表修改 orderInfoVO:{}", orderInfoVO);
        RoomScheduleSaveParam roomScheduleSaveParam = new RoomScheduleSaveParam();
        BeanUtils.copyProperties(orderInfoVO, roomScheduleSaveParam);
        roomScheduleSaveParam.setScheduleDate(orderInfoVO.getAppointmentDate());
        roomScheduleSaveParam.setStatus(RoomStatusEnum.BOOKED.getValue());
        roomScheduleSaveParam.setOrderId(orderInfoVO.getId());
        scheduleService.roomScheduleSave(roomScheduleSaveParam);
    }

    /**
     * 陪玩排班表修改
     */
    private void escortScheduleSaveByOrder(OrderInfoVO orderInfoVO) {
        log.debug("陪玩排班表修改 orderInfoVO:{}", orderInfoVO);

        EscortScheduleSaveParam escortScheduleSaveParam =
                new EscortScheduleSaveParam();
        escortScheduleSaveParam.setScheduleDate(
                orderInfoVO.getAppointmentDate());
        escortScheduleSaveParam.setStartTime(
                orderInfoVO.getStartTime());
        escortScheduleSaveParam.setEndTime(
                orderInfoVO.getEndTime());
        escortScheduleSaveParam.setStatus(
                EscortStatusEnum.BOOKED.getValue());
        escortScheduleSaveParam.setOrderId(orderInfoVO.getId());

        List<Long> escortIdList = orderInfoVO.getEscortIdList();
        if (escortIdList!=null && !escortIdList.isEmpty()) {
            for (Long escortId: escortIdList) {
                escortScheduleSaveParam.setEscortId(escortId);
                scheduleService.escortScheduleSave(escortScheduleSaveParam);
            }
        }
    }

    /**
     * 商家账户相关记录更新
     */
    private void merchantAccountUpdate(OrderInfoVO orderInfoVO, String orderNo) {
        log.debug("商家账户相关记录更新 orderInfoVO:{},orderNo:{}", orderInfoVO, orderNo);

        BigDecimal merchantIncome = orderInfoVO.getPrice().multiply(new BigDecimal("0.95"));

        Long shopId = orderInfoVO.getShopId();
        ShopQuery shopQuery = new ShopQuery();
        shopQuery.setId(shopId);
        List<ShopVO> shopVOList = shopMapper.selectShopVObyShopsQuery(shopQuery);
        if (shopVOList == null || shopVOList.isEmpty()) {
            throw new ServiceException(ResultStatus.DIRTY_DATA, "店家id无效");
        }
        Long merchantId = shopVOList.get(0).getMerchantId();

        MerchantAccountLog merchantAccountLog = new MerchantAccountLog();
        merchantAccountLog.setMerchantId(merchantId);
        merchantAccountLog.setShopId(shopId);
        merchantAccountLog.setOrderNo(orderNo);
        merchantAccountLog.setTransactionTime(new Date());
        merchantAccountLog.setTransactionType(TransactionTypeEnum.TRANSFER_INCOME.getValue());
        merchantAccountLog.setAmount(merchantIncome);
        merchantAccountLog.setCounterparty(platformAccountName);
        merchantAccountService.merchantTransactionRecord(merchantAccountLog);
    }

    /**
     * 根据订单更新个人账户（以及记录）
     */
    private void personalAccountUpdate(
            OrderInfoVO orderInfoVO, TransactionTypeEnum type) {
        log.debug("更新个人账户及其记录 orderInfoVO:{},type:{}", orderInfoVO, type);
        PersonalAccountVO personalAccountVO = personalAccountMapper
                .selectPersonalAccountVObyUserId(orderInfoVO.getUserId());
        if (personalAccountVO == null) {
            throw new ServiceException(ResultStatus.DIRTY_DATA, "账户有误");
        }

        BigDecimal amount = orderInfoVO.getPrice();
        String orderNo = orderInfoVO.getOrderNo();
        PersonalAccountLog accountLog = new PersonalAccountLog();
        accountLog.setPersonalId(personalAccountVO.getId());
        accountLog.setOrderNo(orderNo);
        accountLog.setTransactionType(type.getValue());
        accountLog.setAmount(amount);
        accountLog.setPoints(amount.multiply(new BigDecimal("100")).longValue());
        accountLog.setTMessage(orderInfoVO.getServiceName());
        accountService.accountTransactionRecord(accountLog);
    }
}
